using System;
using System.Linq;
using Anno.Loader;
using Anno.Log;
using Anno.Const;
using Anno;

namespace Anno.DynamicApi
{
    using Anno.EngineData;
    using Anno.Repository;
    using Anno.Rpc.Server;
    using Microsoft.Extensions.DependencyInjection;
    using SqlSugar;
    using System.IO;
    using System.Reflection;

    static class Program
    {
        static void Main(string[] args)
        {
            if (args.Contains("-help"))
            {
                Log.Log.WriteLineAlignNoDate(@"
启动参数：
                -p     6659                    设置启动端口
                -xt    200                     设置服务最大线程数
                -t     20000                   设置超时时间（单位毫秒）
                -w     1                       设置权重
                -h     192.168.0.2             设置服务在注册中心的地址
                -tr    false                   设置调用链追踪是否启用
                --reg  false                   重新注册服务
");
                return;
            }
            Assemblys.AddOtherPlugsAssembly.Add(AddOtherPlugsAssembly);
            //Assemblys.RegisterOtherAssembly.Add(RegisterOtherAssembly);
            Assemblys.BuilderOtherRouterInfo.Add(BuilderOtherRouterInfo);

            /**
             * 启动默认DI库为 Autofac 可以切换为微软自带的DI库 DependencyInjection
             */
            Bootstrap.StartUp(args, () =>//服务配置文件读取完成后回调(服务未启动)
            {
                Anno.Const.SettingService.TraceOnOff = true;

                /*
                 * 功能插件选择是Thrift还是 Grpc
                 * Install-Package Anno.Rpc.Client -Version 1.0.2.6 Thrift
                 * Install-Package Anno.Rpc.ServerGrpc -Version 1.0.1.5 Grpc
                 * 此处为 Thrift
                 */
                //var autofac = IocLoader.GetAutoFacContainerBuilder();
                #region 自带依赖注入过滤器 true  注入 false 不注入
                //IocLoader.AddFilter((type) =>
                //       {
                //           return true;
                //       });
                #endregion
                /**
                 * IRpcConnector 是Anno.EngineData 内置的服务调用接口
                 * 例如：this.InvokeProcessor("Anno.Plugs.SoEasy", "AnnoSoEasy", "SayHi", input)
                 * IRpcConnector 接口用户可以自己实现也可以使用 Thrift或者Grpc Anno内置的实现
                 * 此处使用的是Thrift的实现
                 */
                //autofac.RegisterType(typeof(RpcConnectorImpl)).As(typeof(IRpcConnector)).SingleInstance();
                //autofac.RegisterType(typeof(Anno.EngineData.Cache.ICache)).As(typeof(Anno.EngineData.Cache.MemoryCache)).SingleInstance();

                IocLoader.DiServices.AddSingleton<IRpcConnector, RpcConnectorImpl>();
                IocLoader.DiServices.AddSingleton<EngineData.Cache.ICache, EngineData.Cache.MemoryCache>();
                /*
                  * Anno服务接口通过代理注册到IOC容器中去
                  */
                IocLoader.DiServices.AddSingleton<ITraceLogService>(Rpc.Client.DynamicProxy.AnnoProxyBuilder.GetService<ITraceLogService>());
                IocLoader.DiServices.AddSingleton<ILogService, LogServiceImp>();

                // 注册非泛型仓储
                IocLoader.DiServices.SqlSugarConfigure();
            }
            , () =>//服务启动后的回调方法
            {
                /**
                 * 服务Api文档写入注册中心
                 */
                Bootstrap.ApiDoc();
            }, IocType.DependencyInjection);
        }
        /// <summary>
        /// 添加扩展Assembly
        /// </summary>
        static void AddOtherPlugsAssembly()
        {
            #region 单文件补充
            //var refs = Assembly.GetEntryAssembly().GetReferencedAssemblies().ToList().Where(f => f.Name.StartsWith("Anno.DynamicApi"));
            //foreach (var an in refs)
            //{
            //    if (SettingService.IgnoreFuncNames.Exists(ig => an.Name.ToUpper().Trim().Contains(ig)))
            //    {
            //        continue;
            //    }
            //return;
            try
            {
                Assembly assembly = Assembly.GetEntryAssembly();//Assembly.Load(an);
                var assemblyName = assembly.GetName().Name;
                if (!Anno.Const.Assemblys.Dic.ContainsKey(assemblyName))
                {
                    Anno.Const.Assemblys.Dic.Add(assemblyName, assembly);
                    if (!string.IsNullOrWhiteSpace(SettingService.FuncName))
                    {
                        SettingService.FuncName += ",";
                    }
                    SettingService.FuncName += assemblyName;
                }
                if (AppSettings.IocDll.All(plug => plug != assemblyName))
                {
                    AppSettings.IocDll.Add(assemblyName);
                }
            }
            catch (Exception ex)
            {
                //Console.WriteLine($"插件【{an.Name}】加载出错！");
                Console.WriteLine($"错误信息：");
                Console.WriteLine(ex.Message);
            }
            //}
            #endregion
        }
        /// <summary>
        /// 构建路由信息
        /// </summary>
        /// <param name="svc"></param>
        static void BuilderOtherRouterInfo(Assembly svc, Type baseModuleType)
        {
            try
            {
                var msg = "";
                if (!ControllerList.LoadApiControllers(out msg))
                    throw new Exception("LoadApiControllers Error:" + msg);

                var t = typeof(ApiExecutor);
                var method = t.GetMethodInfo("Executor", new System.Collections.Generic.Dictionary<string, string>());
                foreach (var controllerInfo in ControllerList.ControllerBuilderInfos)
                {
                    if (controllerInfo == null || controllerInfo.ApiInfoList == null || controllerInfo.ApiInfoList.Count == 0)
                        continue;

                    var methods = controllerInfo.ApiInfoList;
                    if (methods == null || methods.Count == 0) continue;
                    //Log.Log.Warn($"正在注册{controllerInfo.ControllerName}Controller......");
                    foreach (var api in methods)
                    {
                        var routInfo = new Anno.EngineData.Routing.RoutInfo()
                        {
                            RoutMethod = method,
                            RoutModuleType = t,
                            Desc = api.Title,
                            HttpMethod = api.HttpMethod,
                            Parameters= new System.Collections.Generic.List<EngineData.Routing.RoutInfo.ParametersValue>()
                        };
                        #region Parameters
                        if (api.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
                        {
                            var comp = api.ExecutorList?.FirstOrDefault();
                            if (comp?.ApiInputInfoList?.Count > 0)
                            {
                                var template = api.ApiName;
                                if (!string.IsNullOrEmpty(api.Route))
                                {
                                    template = api.Route;
                                }
                                foreach (var item in comp.ApiInputInfoList)
                                {
                                    var openApiParameter = new EngineData.Routing.RoutInfo.ParametersValue
                                    {
                                        Name = item.Name,
                                        ParameterType = item.TypeName,
                                        Position= routInfo.Parameters.Count,
                                        Desc = item.Title,
                                    };
                                    routInfo.Parameters.Add(openApiParameter);
                                }
                            }
                        }
                        else
                        {
                            var comp = api.ExecutorList?.FirstOrDefault();
                            if (comp?.ApiInputInfoList?.Count > 0)
                            {
                                foreach (var item in comp.ApiInputInfoList)
                                {
                                    var openApiParameter = new EngineData.Routing.RoutInfo.ParametersValue
                                    {
                                        Name = item.Name,
                                        ParameterType = item.TypeName,
                                        Position = routInfo.Parameters.Count,
                                        Desc = item.Title,
                                    };
                                    routInfo.Parameters.Add(openApiParameter);
                                }
                            }
                            else
                            {
                                var openApiParameter = new EngineData.Routing.RoutInfo.ParametersValue
                                {
                                    Name = "input",
                                    ParameterType = typeof(object).Name,
                                    Position = routInfo.Parameters.Count,
                                    Desc = "input",
                                };
                                routInfo.Parameters.Add(openApiParameter);
                            }
                        }
                        #endregion
                        //-------------------------------------------------------------------------
                        Anno.EngineData.Routing.Routing.Router[api.KeyWord] = routInfo;
                    }
                    //------------------------------------------------------------------------------
                    if (!string.IsNullOrEmpty(Anno.Const.SettingService.FuncName))
                    {
                        Anno.Const.SettingService.FuncName += ",";
                    }
                    Anno.Const.SettingService.FuncName += controllerInfo.RoutePrefix;

                    if (!string.IsNullOrEmpty(Const.SettingService.FuncPath))
                    {
                        Const.SettingService.FuncPath += ",";
                    }
                    Const.SettingService.FuncPath += controllerInfo.RoutePrefix;
                }
            }
            catch (Exception ex)
            {
                Log.Log.Error(ex.ToString());
            }
        }
    }
}
